/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.editor;

import org.gidoo.cms.RedirectPage;
import org.gidoo.cms.editor.edit.EditPanel;
import org.gidoo.cms.editor.history.HistoryPanel;
import org.gidoo.cms.login.GidooCMSSession;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import org.apache.wicket.Component;
import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
import org.apache.wicket.behavior.HeaderContributor;
import org.apache.wicket.extensions.ajax.markup.html.tabs.AjaxTabbedPanel;
import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.html.tree.BaseTree;
import org.apache.wicket.markup.html.tree.ITreeStateListener;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.gidoo.cms.admin.AdminPage;
import org.gidoo.cms.editor.resources.ResourcesPanel;
import org.gidoo.cms.editor.structure.StructurePanel;
import org.gidoo.cms.editor.view.CodeViewPanel;
import org.gidoo.cms.jcr.JcrHelper;
import org.gidoo.wickettools.WicketTools;

/**
 * This is the UI for the editor.
 * @author <a href="mailto:tho.krause@gmail.com">Thomas Krause</a>
 */
@AuthorizeInstantiation(GidooCMSSession.ROLE_EDITOR)
public class EditorPage extends WebPage implements ITreeStateListener
{ 
  
  Label lblTitle;
  Link lnkLogout;
  
  BaseTree treeNav;
  DefaultTreeModel treeNavModel;
  
  DefaultMutableTreeNode root;
  
  AjaxTabbedPanel panelTabs;
  
  FeedbackPanel feedbackPanel;

  String currentSelectedPage;
  
  EditPanel theEditPanel;
  HistoryPanel theHistoryPanel;
  ResourcesPanel theResourcesPanel;
  StructurePanel theStructurePanel;
  CodeViewPanel theCodeViewPanel;
  
  private String lastCutPath = null;
  
  
  /** Creates a new instance of EditorPage */
  public EditorPage()
  {
    add(HeaderContributor.forCss(AdminPage.CSS_ADMIN));
    
    currentSelectedPage = null;
    final EditorPage thePage = this;
    
    feedbackPanel= new FeedbackPanel("feedbackPanel");
    feedbackPanel.setOutputMarkupId(true);
    add(feedbackPanel);
    
    lblTitle = new Label("lblTitle", new Model(getString("editorPage")));
    lnkLogout = new Link("lnkLogout")
    {
      public void onClick()
      {
        GidooCMSSession s = (GidooCMSSession) this.getSession();
        s.signOut();
        setResponsePage(RedirectPage.class);
      }
    };
    
    add(lnkLogout);
    
    add(new Link("lnkRefresh") {
      @Override
      public void onClick()
      {
        thePage.updateDataAndView();
        setResponsePage(thePage);
      }
    });
    
    add(lblTitle);
    
    
    
    // set last CMS-page as selected folder
    GidooCMSSession session = (GidooCMSSession) getSession();
    Node lastVisitedFolder = session.getLastVisitedFolder();
    
    if( lastVisitedFolder != null)
    {
      try
      {
        Node u = session.getJcrRootNode().getNode("users").getNode(session.getUsername());
        Node sectionOfLastVisited = JcrHelper.getSectionOfNode(session.getJcrRootNode(), lastVisitedFolder);
        if (sectionOfLastVisited != null && u.getNode("edit").hasNode(sectionOfLastVisited.getName()))
        {
          currentSelectedPage = lastVisitedFolder.getPath().substring(1);
        }
      }
      catch (RepositoryException ex)
      {
        Logger.getLogger(EditorPage.class.getName()).log(Level.SEVERE, null, ex);
        error(getString("jcrerror"));
      }
    }
    
    createTree();
    
    List<AbstractTab> tabs = new LinkedList<AbstractTab>();

    
    tabs.add(new AbstractTab(new Model(getString("edit"))) {

      @Override
      public Panel getPanel(String panelId)
      {
        theEditPanel = new EditPanel(panelId, getCurrentSelectedPage(), thePage);
        return theEditPanel;
      }
    });
    
    
    tabs.add(new AbstractTab(new Model(getString("view"))) {

      @Override
      public Panel getPanel(String panelId)
      {
        theCodeViewPanel = new CodeViewPanel(panelId, getCurrentSelectedPage());
        return theCodeViewPanel;
      }
    });
    
    
    tabs.add(new AbstractTab(new Model(getString("resources"))) {

      @Override
      public Panel getPanel(String panelId)
      {
        theResourcesPanel = new ResourcesPanel(panelId, getCurrentSelectedPage(), thePage);
        return theResourcesPanel;
      }
    });
    
    tabs.add(new AbstractTab(new Model(getString("history"))) {

      @Override
      public Panel getPanel(String panelId)
      {
        theHistoryPanel = new HistoryPanel(panelId, getCurrentSelectedPage(), thePage);
        return theHistoryPanel;
      }
    });
    
    tabs.add(new AbstractTab(new Model(getString("structure"))) {

      @Override
      public Panel getPanel(String panelId)
      {
        theStructurePanel = new StructurePanel(panelId, getCurrentSelectedPage(), thePage);
        return theStructurePanel;
      }
    });
    
    panelTabs = new AjaxTabbedPanel("panelTabs", tabs);
    panelTabs.setOutputMarkupId(true);  
    add(panelTabs);
    
  }
  
  private void createTree()
  {
    root = new DefaultMutableTreeNode("root");
    treeNavModel = new DefaultTreeModel(root);
    
    treeNav = new BaseTree("treeNav", new Model(treeNavModel))
    {
      protected Component newNodeComponent(String id, IModel model)
      { 
        return new EditorTreePanel(id, model, treeNav);
      }
      
    };
    
    treeNav.setRootLess(true);
    treeNav.getTreeState().addTreeStateListener(this);
    treeNav.getTreeState().collapseAll();
        
    updateTreeModel(getCurrentSelectedPage());
    
    add(treeNav);
    
  }
  
  public void updateDataAndView()
  {
    updateDataAndView(getCurrentSelectedPage());
  }
  
  public void updateDataAndView(Node folderToSelect)
  {
    updateTreeModel(folderToSelect);
    if(theCodeViewPanel != null)
      theCodeViewPanel.updateDataAndView(folderToSelect);
    if(theEditPanel != null)
      theEditPanel.updateDataAndView(folderToSelect, this);
    if(theHistoryPanel != null)
      theHistoryPanel.updateDataAndView(folderToSelect, this);
    if(theResourcesPanel != null)
      theResourcesPanel.updateDataAndView(folderToSelect, this);
     
    // structures doesn't need any updates
  }
  
  private void updateTreeModel(Node folderToSelect)
  {
    if(root != null)
    {
      root.removeAllChildren();
      
      try
      {
        GidooCMSSession session = (GidooCMSSession) getSession();
        NodeIterator it = 
          session.getJcrRootNode().getNode("users/" + session.getUsername() + "/edit").getNodes();
        while(it.hasNext())
        {
          Node tmp = it.nextNode();
          Node s = session.getJcrRootNode().getNode("sections/" + tmp.getName());
          
          JCRTreeNode sNode = new JCRTreeNode(this);
          sNode.setUserObject(s.getPath().substring(1));
          root.add(sNode);
          Node rootFolder = s;
          if(rootFolder != null)
          {            
            populateFolder(rootFolder, sNode, folderToSelect);
            if(rootFolder.equals(folderToSelect) && treeNav != null)
            {
              treeNav.getTreeState().selectNode(sNode, true);
              treeNav.getTreeState().expandNode(sNode);
            }
          }
        }

        
        if(treeNavModel != null)
        {
          treeNavModel.reload();
        }
      }
      catch(Exception ex)
      {
        Logger.getLogger(EditorPage.class.getName()).log(Level.SEVERE, null, ex);
        error("error");
      }
    }
  }
  
  private void populateFolder(Node parentFolder, DefaultMutableTreeNode parentNode, Node folderToSelect)
  {
    try
    {
      if (parentNode != null)
      {
        NodeIterator it = parentFolder.getNodes();
        while(it.hasNext())
        {
          Node c = it.nextNode();
         
          if("cms:page".equals(c.getPrimaryNodeType().getName()))
          {
            JCRTreeNode n = new JCRTreeNode(this);
            n.setUserObject(c.getPath().substring(1));
            parentNode.add(n);
            populateFolder(c, n, folderToSelect);
            if(c.equals(folderToSelect) && treeNav != null)
            {
              treeNav.getTreeState().selectNode(n, true);
              TreeNode nodeToExpand = n;
              while(nodeToExpand != null)
              {
                treeNav.getTreeState().expandNode(nodeToExpand);
                nodeToExpand = nodeToExpand.getParent();
              }
            }
          }
        }
      }
    } catch (RepositoryException ex)
    {
      Logger.getLogger(EditorPage.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }
 
  public void allNodesCollapsed()
  {
  }

  public void allNodesExpanded()
  {
  }

  public void nodeCollapsed(TreeNode node)
  { 
  }

  public void nodeExpanded(TreeNode node)
  {
  }

  public void nodeSelected(TreeNode node)
  {
    treeNav.getTreeState().expandNode(node);
    DefaultMutableTreeNode n = (DefaultMutableTreeNode) node;
    Object o = n.getUserObject();
    if(o instanceof String)
    {
      currentSelectedPage = (String) o;    
    }
    else
    {
      currentSelectedPage = null;
    }
    
    if(panelTabs != null)
    {
      panelTabs.setSelectedTab(panelTabs.getSelectedTab());
      WicketTools.addToAjaxRequestTarget(new Component[] {feedbackPanel, panelTabs}, this);
    }
  }

  public void nodeUnselected(TreeNode node)
  {
    currentSelectedPage = null;
    panelTabs.setSelectedTab(panelTabs.getSelectedTab());
    
    WicketTools.addToAjaxRequestTarget(new Component[] {feedbackPanel, panelTabs}, this);
  }
  
  public Node getCurrentSelectedPage()
  {
    if(currentSelectedPage == null)
    {
      return null;
    }
    
    try
    {
      Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
      Node result = rootNode.getNode(currentSelectedPage);
      return result;
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(EditorPage.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
  }
 
  
  
  public BaseTree getTreeNav()
  {
    return treeNav;
  }

  public FeedbackPanel getFeedbackPanel()
  {
    return feedbackPanel;
  }

  public AjaxTabbedPanel getPanelTabs()
  {
    return panelTabs;
  }
  
  
  /** Get the ID of the last "cutted" page */
  public String getLastCutPath()
  {
    return lastCutPath;
  }

  /**Get the ID of the last "cutted" page */
  public void setLastCutPath(String lastCutPath)
  {
    this.lastCutPath = lastCutPath;
  }
  
}
